package com.ruibang.glass.quality.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruibang.glass.common.utils.DataUtils;
import com.ruibang.glass.frequencycontrol.annotation.RedissonLock;
import com.ruibang.glass.quality.constant.Constants;
import com.ruibang.glass.quality.domain.req.*;
import com.ruibang.glass.quality.domain.resp.DefectDetailResp;
import com.ruibang.glass.quality.domain.resp.DiscardData;
import com.ruibang.glass.quality.domain.resp.ExternalDefectOverlayMap;
import com.ruibang.glass.quality.domain.resp.ReceivePackage;
import com.ruibang.glass.quality.entity.*;
import com.ruibang.glass.quality.mapper.TotalEquDataMapper;
import com.ruibang.glass.quality.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author wujie
 * @since 2020-08-06
 */
@Slf4j
@Service
public class TotalEquDataServiceImpl extends ServiceImpl<TotalEquDataMapper, TotalEquData> implements TotalEquDataService {

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    private DictService dictService;

    @Autowired
    private DefectGroupService defectGroupService;

    @Autowired
    private EverydayDiscardDefectService everydayDiscardDefectService;

    @Autowired
    private EveryHourDiscardDefectService everyHourDiscardDefectService;

    @Autowired
    private DiscardDefectDataService discardDefectDataService;

    @Autowired
    private EverydayHotEndDiscardDefectService everydayHotEndDiscardDefectService;

    @Autowired
    private EveryHourHotEndDiscardDefectService everyHourHotEndDiscardDefectService;

    @Autowired
    private HotEndDiscardDefectDataService hotEndDiscardDefectDataService;

    @Autowired
    private EveryHourColdDirectService everyHourColdDirectService;

    @Autowired
    private EverydayColdDirectService everydayColdDirectService;

    @Autowired
    private EverydayDefectLossService everydayDefectLossService;

    @Autowired
    private EveryHourDefectLossService everyHourDefectLossService;


    @Override
    public List<BandDefectData> queryBandDefectData(String selectSql) {
        return baseMapper.queryBandDefectData(selectSql);
    }

    @Override
    public List<DefectDetailResp> queryDefectDetailData(String selectSql) {
        return baseMapper.queryDefectDetailData(selectSql);
    }

    @Override
    public List<EveryHourArchiveDefect> queryEveryHourArchiveDefect(ArchiveDefectReq archiveDefectReq) {
        //获取检查机CM1对应查询条件
        List<Defect> defects = defectGroupService.getByCheckMachine("CM1", Constants.ZERO_STR);
        if (CollectionUtils.isNotEmpty(defects)) {

            for (Defect defect : defects) {
                if (Constants.DEFECT_BUBBLE.equals(defect.getDefectCode())) { //Bubble
                    archiveDefectReq.setBubbleSql(assembleSql(archiveDefectReq.getBubbleSql(), defect));
                } else if (defect.getDefectCode().contains("Open Bubble")) {//Open Bubble
                    archiveDefectReq.setOpenBubbleSql(assembleSql(archiveDefectReq.getOpenBubbleSql(), defect));
                } else if (Constants.DEFECT_STONE.equals(defect.getDefectCode())) { //Stone
                    archiveDefectReq.setStoneSql(assembleSql(archiveDefectReq.getStoneSql(), defect));
                } else if (defect.getDefectCode().contains("PT")) { //PT
                    archiveDefectReq.setPtSql(assembleSql(archiveDefectReq.getPtSql(), defect));
                }
            }
        }

        if (StringUtils.isNotBlank(archiveDefectReq.getBubbleSql())) {
            archiveDefectReq.setBubbleSql(archiveDefectReq.getBubbleSql().concat(") "));
        }

        if (StringUtils.isNotBlank(archiveDefectReq.getOpenBubbleSql())) {
            archiveDefectReq.setOpenBubbleSql(archiveDefectReq.getOpenBubbleSql().concat(") "));
        }

        if (StringUtils.isNotBlank(archiveDefectReq.getStoneSql())) {
            archiveDefectReq.setStoneSql(archiveDefectReq.getStoneSql().concat(") "));
        }

        if (StringUtils.isNotBlank(archiveDefectReq.getPtSql())) {
            archiveDefectReq.setPtSql(archiveDefectReq.getPtSql().concat(") "));
        }

        List<EveryHourArchiveDefect> archiveDefects = baseMapper.queryEveryHourArchiveDefect(archiveDefectReq);

        return archiveDefects;
    }

    @Override
    public List<EverydayArchiveDefect> queryEverydayArchiveDefect(ArchiveDefectReq archiveDefectReq) {
        //获取检查机CM1对应查询条件
        List<Defect> defects = defectGroupService.getByCheckMachine("CM1", Constants.ZERO_STR);
        if (CollectionUtils.isNotEmpty(defects)) {

            for (Defect defect : defects) {
                if (Constants.DEFECT_BUBBLE.equals(defect.getDefectCode())) { //Bubble
                    archiveDefectReq.setBubbleSql(assembleSql(archiveDefectReq.getBubbleSql(), defect));
                } else if (defect.getDefectCode().contains("Open Bubble")) {//Open Bubble
                    archiveDefectReq.setOpenBubbleSql(assembleSql(archiveDefectReq.getOpenBubbleSql(), defect));
                } else if (Constants.DEFECT_STONE.equals(defect.getDefectCode())) { //Stone
                    archiveDefectReq.setStoneSql(assembleSql(archiveDefectReq.getStoneSql(), defect));
                } else if (defect.getDefectCode().contains("PT")) { //PT
                    archiveDefectReq.setPtSql(assembleSql(archiveDefectReq.getPtSql(), defect));
                }
            }
        }

        if (StringUtils.isNotBlank(archiveDefectReq.getBubbleSql())) {
            archiveDefectReq.setBubbleSql(archiveDefectReq.getBubbleSql().concat(") "));
        }

        if (StringUtils.isNotBlank(archiveDefectReq.getOpenBubbleSql())) {
            archiveDefectReq.setOpenBubbleSql(archiveDefectReq.getOpenBubbleSql().concat(") "));
        }

        if (StringUtils.isNotBlank(archiveDefectReq.getStoneSql())) {
            archiveDefectReq.setStoneSql(archiveDefectReq.getStoneSql().concat(") "));
        }

        if (StringUtils.isNotBlank(archiveDefectReq.getPtSql())) {
            archiveDefectReq.setPtSql(archiveDefectReq.getPtSql().concat(") "));
        }

        List<EverydayArchiveDefect> archiveDefects = baseMapper.queryEverydayArchiveDefect(archiveDefectReq);

        return archiveDefects;
    }

    @Override
    public List<ExternalDefectOverlayMap> queryExternalDefectOverlayMap(ExternalDefectReq externalDefectReq) {
        return baseMapper.queryExternalDefectOverlayMap(externalDefectReq);
    }

    /***
     * 组装归档缺陷统计查询条件
     * @param oldSql
     * @param defect
     * @return
     */
    private String assembleSql(String oldSql, Defect defect) {
        StringBuilder sql = new StringBuilder("");
        if (StringUtils.isNotBlank(oldSql)) {
            sql.append(oldSql);
            sql.append(" or ( ");
        } else {
            sql.append(" and (( ");
        }
        double minSize = defect.getMinSize() / 1000f;
        double maxSize = defect.getMaxSize() / 1000f;
        sql.append("TiltedSize >= ").append(minSize);
        sql.append(" AND TiltedSize <= ").append(maxSize);
        sql.append(" AND TiltedDiv >= ").append(defect.getMinLayerDepth());
        sql.append(" AND TiltedDiv <= ").append(defect.getMaxLayerDepth());
        sql.append(") ");

        return sql.toString();
    }


    @Override
    public List<ReceivePackage> queryTodayReceiveData(String currentDay) {
        return baseMapper.queryTodayReceiveData(currentDay);
    }

    @Override
    public List<EveryHourColdDirectLoss> queryEveryHourColdDirect(String currentDay) {
        return baseMapper.queryEveryHourColdDirect(currentDay);
    }

    @Override
    public EverydayColdDirectLoss queryEverydayHourColdDirect(String currentDay) {
        return baseMapper.queryEverydayHourColdDirect(currentDay);
    }

    @Override
    public List<EverydayDefectLoss> queryEverydayDefectLose(DefectLossReq defectLossReq) {
        List<EverydayDefectLoss> coldEverydayDefectLosses = baseMapper.queryColdEverydayDefectLose(defectLossReq);
        List<EverydayDefectLoss> hotEverydayDefectLosses = baseMapper.queryHotEverydayDefectLose(defectLossReq);
        List<EverydayDefectLoss> data = new ArrayList<>();
        List<String> datesBetween = getDatesBetween(LocalDate.parse(defectLossReq.getStartDate()), LocalDate.parse(defectLossReq.getEndDate()));
        if (CollectionUtils.isNotEmpty(datesBetween)) {
            Map<String, EverydayDefectLoss> coldMap = null;
            Map<String, EverydayDefectLoss> hotMap = null;
            if (CollectionUtils.isNotEmpty(coldEverydayDefectLosses)) {
                coldMap = coldEverydayDefectLosses.stream().collect(Collectors.toMap(EverydayDefectLoss::getDefectDateKey, e -> e));
            }
            if (CollectionUtils.isNotEmpty(hotEverydayDefectLosses)) {
                hotMap = hotEverydayDefectLosses.stream().collect(Collectors.toMap(EverydayDefectLoss::getDefectDateKey, e -> e));
            }

            for (String date : datesBetween) {
                EverydayDefectLoss everydayDefectLoss = new EverydayDefectLoss();
                LocalDate time = LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyyMMdd"));
                everydayDefectLoss.setDefectDate(time);
                everydayDefectLoss.setDefectDateKey(date);
                //冷端
                if (coldMap != null) {
                    EverydayDefectLoss coldEverydayDefectLoss = coldMap.get(date);
                    if (coldEverydayDefectLoss != null) {
                        everydayDefectLoss.setColdBubbleNum(coldEverydayDefectLoss.getColdBubbleNum());
                        everydayDefectLoss.setColdOpenBubbleNum(coldEverydayDefectLoss.getColdOpenBubbleNum());
                        everydayDefectLoss.setColdStoneNum(coldEverydayDefectLoss.getColdStoneNum());
                        everydayDefectLoss.setPlatinumNum(coldEverydayDefectLoss.getPlatinumNum());
                        everydayDefectLoss.setFinishedNum(coldEverydayDefectLoss.getFinishedNum());
                    }
                }
                //热端
                if (hotMap != null) {
                    EverydayDefectLoss hotEverydayDefectLoss = hotMap.get(date);
                    if (hotEverydayDefectLoss != null) {
                        everydayDefectLoss.setHotBubbleNum(hotEverydayDefectLoss.getHotBubbleNum());
                        everydayDefectLoss.setHotStoneNum(hotEverydayDefectLoss.getHotStoneNum());
                        everydayDefectLoss.setSemiFinishedNum(hotEverydayDefectLoss.getSemiFinishedNum());
                    }
                }
                data.add(everydayDefectLoss);
            }
        }
        return data;
    }

    public static List<String> getDatesBetween(LocalDate startDate, LocalDate endDate) {
        List<String> datesList = new ArrayList<>();
        LocalDate currentDate = startDate;
        while (!currentDate.isAfter(endDate)) {
            datesList.add(currentDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")));
            currentDate = currentDate.plusDays(1);
        }
        return datesList;
    }

    public static List<String> getDateTimeBetween(LocalDate startDate, LocalDate endDate) {
        List<String> dateTimeList = new ArrayList<>();
        LocalDateTime startDateTime = startDate.atStartOfDay();
        LocalDateTime endDateTime = endDate.atTime(23, 59);
        LocalDateTime currentDateTime = startDateTime;
        while (!currentDateTime.isAfter(endDateTime)) {
            dateTimeList.add(currentDateTime.format(DateTimeFormatter.ofPattern("yyyyMMddHH")));
            currentDateTime = currentDateTime.plusHours(1);
        }
        return dateTimeList;
    }

    public static void main(String[] args) {
        LocalDate startDate = LocalDate.of(2024, 4, 1);
        LocalDate endDate = LocalDate.of(2024, 4, 1);
        List<String> dateTimes = getDateTimeBetween(startDate, endDate);
        for (String dateTime : dateTimes) {
            System.out.println(dateTime);
        }
    }

    @Override
    public List<EveryHourDefectLoss> queryEveryHourDefectLose(DefectLossReq defectLossReq) {
        List<EveryHourDefectLoss> coldEverydayDefectLosses = baseMapper.queryColdEveryHourDefectLose(defectLossReq);
        List<EveryHourDefectLoss> hotEverydayDefectLosses = baseMapper.queryHotEveryHourDefectLose(defectLossReq);
        List<EveryHourDefectLoss> data = new ArrayList<>();
        List<String> dateTimeBetween = getDateTimeBetween(LocalDate.parse(defectLossReq.getStartDate()), LocalDate.parse(defectLossReq.getEndDate()));
        if (CollectionUtils.isNotEmpty(dateTimeBetween)) {
            Map<String, EveryHourDefectLoss> coldMap = null;
            Map<String, EveryHourDefectLoss> hotMap = null;
            if (CollectionUtils.isNotEmpty(coldEverydayDefectLosses)) {
                coldMap = coldEverydayDefectLosses.stream().collect(Collectors.toMap(EveryHourDefectLoss::getDefectTimeKey, e -> e));
            }
            if (CollectionUtils.isNotEmpty(hotEverydayDefectLosses)) {
                hotMap = hotEverydayDefectLosses.stream().collect(Collectors.toMap(EveryHourDefectLoss::getDefectTimeKey, e -> e));
            }

            for (String dateTime : dateTimeBetween) {
                EveryHourDefectLoss everydayDefectLoss = new EveryHourDefectLoss();
                LocalDateTime time = LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern("yyyyMMddHH"));
                everydayDefectLoss.setDefectTime(time);
                everydayDefectLoss.setDefectTimeKey(dateTime);
                //冷端
                if (coldMap != null) {
                    EveryHourDefectLoss coldEveryHourDefectLoss = coldMap.get(dateTime);
                    if (coldEveryHourDefectLoss != null) {
                        everydayDefectLoss.setColdBubbleNum(coldEveryHourDefectLoss.getColdBubbleNum());
                        everydayDefectLoss.setColdOpenBubbleNum(coldEveryHourDefectLoss.getColdOpenBubbleNum());
                        everydayDefectLoss.setColdStoneNum(coldEveryHourDefectLoss.getColdStoneNum());
                        everydayDefectLoss.setPlatinumNum(coldEveryHourDefectLoss.getPlatinumNum());
                        everydayDefectLoss.setFinishedNum(coldEveryHourDefectLoss.getFinishedNum());
                    }
                }
                //热端
                if (hotMap != null) {
                    EveryHourDefectLoss hotEveryHourDefectLoss = hotMap.get(dateTime);
                    if (hotEveryHourDefectLoss != null) {
                        everydayDefectLoss.setHotBubbleNum(hotEveryHourDefectLoss.getHotBubbleNum());
                        everydayDefectLoss.setHotStoneNum(hotEveryHourDefectLoss.getHotStoneNum());
                        everydayDefectLoss.setSemiFinishedNum(hotEveryHourDefectLoss.getSemiFinishedNum());
                    }
                }
                data.add(everydayDefectLoss);
            }
        }
        return data;
    }


    /**
     * importHotEndDiscardDefectData 有两个相同地方加锁  防止两边同时执行
     * 热端曲线支撑数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @RedissonLock(key = "#defectHourTaskReq.checkMachineCode", prefixKey = "importHotEndDiscardDefectData")
    public void importHotEndDiscardDefectData(DefectHourTaskReq defectHourTaskReq) {
        log.error("importDiscardDefectData defectHourTaskReq:{}", defectHourTaskReq);

        List<Defect> defects = defectGroupService.getByCheckMachine(defectHourTaskReq.getCheckMachineCode(), Constants.ONE_STR);

        if (CollectionUtils.isNotEmpty(defects)) {
            StringBuilder sql = new StringBuilder();
            AtomicInteger i = new AtomicInteger(1);

            Map<String, List<Defect>> defectMap = defects.stream().collect(Collectors.groupingBy(e -> e.getDefectName() + "_" + e.getDefectCode()));
            String startTime = defectHourTaskReq.getStartTime();
            String endTime = defectHourTaskReq.getEndTime();
            defectMap.forEach((k, v) -> {
                String[] split = k.split("_");
                String defectCode = split[1];
                String defectName = split[0];

                if (i.get() > 1) {
                    sql.append(" union ");
                }
                sql.append("SELECT CustomerPanelId,DefectName,StartTime as StartTime,MaterialCenterDW,MaterialCenterCW,TiltedSize,TiltedDiv FROM total_equ_data where ");
                sql.append("is_finished = ").append(0).append(" AND MachineId ='Inspect' ");

                sql.append("AND DefectName = '").append(defectCode).append("' AND(");
                for (int j = 0; j < v.size(); j++) {
                    Defect value = v.get(j);
                    sql.append("(");
                    double minSize = value.getMinSize() / 1000f;
                    double maxSize = value.getMaxSize() / 1000f;
                    sql.append("TiltedSize >= ").append(minSize);
                    sql.append(" AND TiltedSize <= ").append(maxSize);

                    if (j == v.size() - 1) {
                        sql.append(")");
                    } else {
                        sql.append(") or ");
                    }
                }

                sql.append(") AND StartTime >= ").append("'").append(startTime).append("' AND StartTime ").append(" <= ");
                sql.append("'").append(endTime).append("'");
                i.getAndIncrement();
            });

            log.error("支撑热端判废数据 执行查询语句{}:{}", "热端", sql);
            List<DiscardDefectData> discardDatas = baseMapper.queryDiscardDefectData(sql.toString());

            //保存热端、冷端数据
            if (CollectionUtils.isNotEmpty(discardDatas)) {
                //热端
                List<HotEndDiscardDefectData> hotEnd = new ArrayList<>();
                for (DiscardDefectData discardDefectData : discardDatas) {
                    HotEndDiscardDefectData hotEndDiscardDefectData = new HotEndDiscardDefectData();
                    hotEndDiscardDefectData.setCustomerPanelId(discardDefectData.getCustomerPanelId());
                    hotEndDiscardDefectData.setDefectName(discardDefectData.getDefectName());
                    hotEndDiscardDefectData.setStartTime(discardDefectData.getStartTime());
                    hotEndDiscardDefectData.setMaterialCenterDW(discardDefectData.getMaterialCenterDW());
                    hotEndDiscardDefectData.setMaterialCenterCW(discardDefectData.getMaterialCenterCW());
                    hotEndDiscardDefectData.setTiltedSize(discardDefectData.getTiltedSize());
                    hotEndDiscardDefectData.setTiltedDiv(discardDefectData.getTiltedDiv());
                    hotEnd.add(hotEndDiscardDefectData);
                }
                hotEndDiscardDefectDataService.deleteByDateTime(defectHourTaskReq);
                //保存热端数据
                if (hotEnd.size() >= 10000) {
                    List<List<HotEndDiscardDefectData>> batch = DataUtils.batch(hotEnd, 5000);
                    List<CompletableFuture<Void>> completableFutureList = new ArrayList<>();
                    batch.forEach(e -> {
                        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> hotEndDiscardDefectDataService.saveBatch(e, 2500),threadPoolTaskExecutor);
                        completableFutureList.add(completableFuture);
                    });
                    log.error("插入线程数：{}", completableFutureList.size());
                    for (CompletableFuture<Void> completableFuture : completableFutureList) {
                        completableFuture.join();
                    }
                } else {
                    hotEndDiscardDefectDataService.saveBatch(hotEnd);
                }

            }
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    @RedissonLock(key = "#defectReq.checkMachineCode", prefixKey = "import_every_hour_discard_defect")
    public void importEveryHourDiscardDefect(DiscardDefectReq defectReq) {
        log.error("importEveryHourDiscardDefect defectReq;{}", defectReq);
        if (defectReq == null) {
            defectReq = setDefaultTime();
        }
        StringBuilder sql = new StringBuilder();
        List<String> types = new ArrayList<>();
        types.add(Constants.STONE);
        types.add(Constants.PT);
        types.add(Constants.BUBBLE);
        List<DictInfo> dictInfos = dictService.queryByGroupType(types);
        if (CollectionUtils.isNotEmpty(dictInfos)) {
            Map<String, List<DictInfo>> dictMap = dictInfos.stream().collect(Collectors.groupingBy(DictInfo::getGroupType));

            List<Defect> defects = defectGroupService.getByCheckMachine(defectReq.getCheckMachineCode(), defectReq.getCheckMachineType());

            if (CollectionUtils.isNotEmpty(defects)) {
                String startDate = defectReq.getStartDate();
                String endDate = defectReq.getEndDate();
                String isFinished = defectReq.getIsFinished();
                String checkMachineType = defectReq.getCheckMachineType();

                Map<String, String> discardField = new HashMap<>();
                Map<String, List<Defect>> defectMap = defects.stream().collect(Collectors.groupingBy(e -> e.getDefectName() + "_" + e.getDefectCode()));

                AtomicInteger i = new AtomicInteger();
                StringBuilder head = new StringBuilder("SELECT t0.discardDateKey,t0.checkNum,");
                StringBuilder body = new StringBuilder(" (select count(DISTINCT CustomerBatchId) as checkNum,");
                body.append("DATE_FORMAT(StartTime,'%Y%m%d%H') AS discardDateKey from total_equ_data where MachineId ='Inspect' ");
                body.append("AND is_finished = ").append(isFinished);
                if (Constants.ZERO_STR.equals(defectReq.getCheckMachineType())) {
                    body.append(" AND (CustomerBatchId LIKE '66%' OR CustomerBatchId LIKE '02%')");
                }
                body.append(" AND DATE_FORMAT(StartTime,'%Y-%m-%d') between ");
                body.append("'").append(startDate).append("'").append(" AND ").append("'").append(endDate).append("'");
                body.append(" GROUP BY DATE_FORMAT(StartTime,'%Y%m%d%H')) t0");
                defectMap.forEach((k, v) -> {
                    String[] split = k.split("_");
                    String defectCode = split[1];
                    String defectName = split[0];

                    i.getAndIncrement();
                    String tableName = "t" + i;
                    String field = "data" + i;
                    head.append(tableName).append(".").append(field).append(",");
                    body.append(" LEFT JOIN ");
                    body.append(" (select count(DISTINCT CustomerBatchId) as ").append(field).append(",");
                    body.append("DATE_FORMAT(StartTime,'%Y%m%d%H') AS discardDateKey from total_equ_data where ");
                    body.append("is_finished = ").append(isFinished);
                    body.append(" AND MachineId ='Inspect' ");
                    if (Constants.ZERO_STR.equals(checkMachineType)) {
                        body.append("AND (CustomerBatchId LIKE '66%' OR CustomerBatchId LIKE '02%')");
                    }
                    body.append(" AND DefectName = ");
                    body.append("'").append(defectCode).append("' AND(");
                    for (int j = 0; j < v.size(); j++) {
                        Defect value = v.get(j);
                        body.append("(");
                        double minSize = value.getMinSize() / 1000f;
                        double maxSize = value.getMaxSize() / 1000f;
                        body.append("TiltedSize >= ").append(minSize);
                        body.append(" AND TiltedSize <= ").append(maxSize);

                        if (Constants.ZERO_STR.equals(checkMachineType)) {
                            body.append(" AND TiltedDiv >= ").append(value.getMinLayerDepth());
                            body.append(" AND TiltedDiv <= ").append(value.getMaxLayerDepth());
                        }

                        if (j == v.size() - 1) {
                            body.append(")");
                        } else {
                            body.append(") or ");
                        }
                    }
                    body.append(") AND DATE_FORMAT(StartTime,'%Y-%m-%d') between ").append("'").append(startDate).append("'").append(" AND ");
                    body.append("'").append(endDate).append("'");
                    body.append(" GROUP BY DATE_FORMAT(StartTime,'%Y%m%d%H')) ").append(tableName);
                    body.append(" ON t0").append(".discardDateKey = ").append(tableName).append(".discardDateKey ");
                    discardField.put(defectCode, field);

                });


                sql.append(head.toString().substring(0, head.length() - 1));
                sql.append(" FROM ");
                sql.append(body);


                log.error("每小时执行查询语句{}:{}", defectReq.getCheckMachineType().equals(Constants.ZERO_STR) ? "冷端" : "热端", sql);

                List<DiscardData> discardData = baseMapper.queryEverydayDiscard(sql.toString());
                if (CollectionUtils.isNotEmpty(discardData)) {
                    List<EveryHourDiscardDefect> discardDefects = new ArrayList<>();
                    for (DiscardData discard : discardData) {
                        EveryHourDiscardDefect discardDefect = new EveryHourDiscardDefect();
                        LocalDateTime time = LocalDateTime.parse(discard.getDiscardDateKey().concat("0000"), DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
                        discardDefect.setDiscardDate(time);
                        List<DictInfo> bubbleDicts = dictMap.get(Constants.BUBBLE);
                        if (CollectionUtils.isNotEmpty(bubbleDicts)) {
                            Map<String, DictInfo> bubbleDictMap = bubbleDicts.stream().collect(Collectors.toMap(DictInfo::getValue, e -> e));
                            DictInfo bDictInfo = bubbleDictMap.get(Constants.BUBBLE);
                            DictInfo obDictInfo = bubbleDictMap.get(Constants.OPEN_BUBBLE);
                            if (bDictInfo != null) {
                                discardDefect.setBubbleDiscardNum(getDefectNum(Collections.singletonList(bDictInfo), discard, discardField));
                            }
                            if (obDictInfo != null) {
                                discardDefect.setOpenBubbleDiscardNum(getDefectNum(Collections.singletonList(obDictInfo), discard, discardField));
                            }
                        }

                        List<DictInfo> ptDicts = dictMap.get(Constants.PT);
                        if (CollectionUtils.isNotEmpty(ptDicts)) {
                            discardDefect.setPlatinumDiscardNum(getDefectNum(ptDicts, discard, discardField));
                        }


                        List<DictInfo> stoneDicts = dictMap.get(Constants.STONE);
                        if (CollectionUtils.isNotEmpty(stoneDicts)) {
                            discardDefect.setStoneDiscardNum(getDefectNum(stoneDicts, discard, discardField));
                        }

                        discardDefect.setCheckNum(discard.getCheckNum());

                        float bubbleRate = discardDefect.getBubbleDiscardNum() / (float) discard.getCheckNum();
                        discardDefect.setBubbleDiscardRate(bubbleRate);

                        float openBubbleRate = discardDefect.getOpenBubbleDiscardNum() / (float) discard.getCheckNum();
                        discardDefect.setOpenBubbleDiscardRate(openBubbleRate);

                        float ptRate = discardDefect.getPlatinumDiscardNum() / (float) discard.getCheckNum();
                        discardDefect.setPlatinumDiscardRate(ptRate);

                        float stoneRate = discardDefect.getStoneDiscardNum() / (float) discard.getCheckNum();
                        discardDefect.setStoneDiscardRate(stoneRate);
                        discardDefect.setCheckMachineCode(defectReq.getCheckMachineCode());

                        discardDefects.add(discardDefect);
                    }

                    //保存热端、冷端数据
                    if (CollectionUtils.isNotEmpty(discardDefects)) {
                        //判斷是冷端还是热端 0:冷端，1:热端
                        if (Constants.ZERO_STR.equals(checkMachineType)) {
                            //冷端
                            everyHourDiscardDefectService.deleteByDate(defectReq);
                            everyHourDiscardDefectService.saveBatch(discardDefects);
                        } else {
                            //热端
                            List<EveryHourHotEndDiscardDefect> hotEnd = new ArrayList<>();
                            for (EveryHourDiscardDefect discardDefect : discardDefects) {
                                EveryHourHotEndDiscardDefect everyHourHotEndDiscardDefect = new EveryHourHotEndDiscardDefect();
                                everyHourHotEndDiscardDefect.setDiscardDate(discardDefect.getDiscardDate());
                                everyHourHotEndDiscardDefect.setBubbleDiscardNum(discardDefect.getBubbleDiscardNum());
                                everyHourHotEndDiscardDefect.setStoneDiscardNum(discardDefect.getStoneDiscardNum());
                                everyHourHotEndDiscardDefect.setPlatinumDiscardNum(discardDefect.getPlatinumDiscardNum());
                                everyHourHotEndDiscardDefect.setCheckNum(discardDefect.getCheckNum());
                                everyHourHotEndDiscardDefect.setBubbleDiscardRate(discardDefect.getBubbleDiscardRate());
                                everyHourHotEndDiscardDefect.setStoneDiscardRate(discardDefect.getStoneDiscardRate());
                                everyHourHotEndDiscardDefect.setPlatinumDiscardRate(discardDefect.getPlatinumDiscardRate());
                                everyHourHotEndDiscardDefect.setCheckMachineCode(discardDefect.getCheckMachineCode());
                                hotEnd.add(everyHourHotEndDiscardDefect);
                            }
                            //保存热端数据
                            everyHourHotEndDiscardDefectService.deleteByDate(defectReq);
                            everyHourHotEndDiscardDefectService.saveBatch(hotEnd);
                        }
                    }
                }
            }
        }
    }


    /**
     * 每日判废数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importEverydayDiscardDefect(DiscardDefectReq defectReq) {
        log.error("importEverydayDiscardDefect defectReq:{}", defectReq);
        //设置默认时间
        if (defectReq == null) {
            defectReq = setDefaultTime();
        }
        StringBuilder sql = new StringBuilder();
        List<String> types = new ArrayList<>();
        types.add(Constants.STONE);
        types.add(Constants.PT);
        types.add(Constants.BUBBLE);
        List<DictInfo> dictInfos = dictService.queryByGroupType(types);
        if (CollectionUtils.isNotEmpty(dictInfos)) {
            Map<String, List<DictInfo>> dictMap = dictInfos.stream().collect(Collectors.groupingBy(DictInfo::getGroupType));

            //暂时默认为第一个检查机code='CM1'
            List<Defect> defects = defectGroupService.getByCheckMachine(defectReq.getCheckMachineCode(), defectReq.getCheckMachineType());

            if (CollectionUtils.isNotEmpty(defects)) {
                Map<String, String> discardField = new HashMap<>();

                Map<String, List<Defect>> defectMap = defects.stream().collect(Collectors.groupingBy(e -> e.getDefectName() + "_" + e.getDefectCode()));
                String startDate = defectReq.getStartDate();
                String endDate = defectReq.getEndDate();
                String isFinished = defectReq.getIsFinished();
                String checkMachineType = defectReq.getCheckMachineType();

                AtomicInteger i = new AtomicInteger();
                StringBuilder head = new StringBuilder("SELECT t0.discardDateKey,t0.checkNum,");
                StringBuilder body = new StringBuilder(" (select count(DISTINCT CustomerBatchId) as checkNum,");
                body.append("DATE_FORMAT(StartTime,'%Y%m%d') AS discardDateKey from total_equ_data where MachineId ='Inspect' ");
                body.append("AND is_finished = ").append(isFinished);
                if (Constants.ZERO_STR.equals(checkMachineType)) {
                    body.append(" AND (CustomerBatchId LIKE '66%' OR CustomerBatchId LIKE '02%')");
                }
                body.append(" AND DATE_FORMAT(StartTime,'%Y-%m-%d') between ");
                body.append("'").append(startDate).append("'").append(" AND ").append("'").append(endDate).append("'");
                body.append(" GROUP BY DATE_FORMAT(StartTime,'%Y%m%d')) t0");
                defectMap.forEach((k, v) -> {
                    String[] split = k.split("_");
                    String defectCode = split[1];
                    String defectName = split[0];

                    i.getAndIncrement();
                    String tableName = "t" + i;
                    String field = "data" + i;
                    head.append(tableName).append(".").append(field).append(",");
                    body.append(" LEFT JOIN ");
                    body.append(" (select count(DISTINCT CustomerBatchId) as ").append(field).append(",");
                    body.append("DATE_FORMAT(StartTime,'%Y%m%d') AS discardDateKey from total_equ_data where ");
                    body.append("is_finished = ").append(isFinished);
                    body.append(" AND MachineId ='Inspect' ");
                    if (Constants.ZERO_STR.equals(checkMachineType)) {
                        body.append("AND (CustomerBatchId LIKE '66%' OR CustomerBatchId LIKE '02%')");
                    }
                    body.append(" AND DefectName = '").append(defectCode).append("' AND(");
                    for (int j = 0; j < v.size(); j++) {
                        Defect value = v.get(j);
                        body.append("(");
                        double minSize = value.getMinSize() / 1000f;
                        double maxSize = value.getMaxSize() / 1000f;
                        body.append("TiltedSize >= ").append(minSize);
                        body.append(" AND TiltedSize <= ").append(maxSize);

                        if (Constants.ZERO_STR.equals(checkMachineType)) {
                            body.append(" AND TiltedDiv >= ").append(value.getMinLayerDepth());
                            body.append(" AND TiltedDiv <= ").append(value.getMaxLayerDepth());
                        }

                        if (j == v.size() - 1) {
                            body.append(")");
                        } else {
                            body.append(") or ");
                        }
                    }
                    body.append(") AND DATE_FORMAT(StartTime,'%Y-%m-%d') between ").append("'").append(startDate).append("'").append(" AND ");
                    body.append("'").append(endDate).append("'");
                    body.append(" GROUP BY DATE_FORMAT(StartTime,'%Y%m%d')) ").append(tableName);
                    body.append(" ON t0").append(".discardDateKey = ").append(tableName).append(".discardDateKey ");
                    discardField.put(defectCode, field);
                });

                sql.append(head.toString().substring(0, head.length() - 1));
                sql.append(" FROM ");
                sql.append(body);

                log.error("每日执行查询语句{}:{}", defectReq.getCheckMachineType().equals(Constants.ZERO_STR) ? "冷端" : "热端", sql);

                List<DiscardData> discardData = baseMapper.queryEverydayDiscard(sql.toString());
                if (CollectionUtils.isNotEmpty(discardData)) {
                    List<EverydayDiscardDefect> discardDefects = new ArrayList<>();
                    for (DiscardData discard : discardData) {
                        EverydayDiscardDefect discardDefect = new EverydayDiscardDefect();
                        LocalDate date = LocalDate.parse(discard.getDiscardDateKey(), DateTimeFormatter.ofPattern("yyyyMMdd"));
                        discardDefect.setDiscardDate(date);
                        List<DictInfo> bubbleDicts = dictMap.get(Constants.BUBBLE);
                        if (CollectionUtils.isNotEmpty(bubbleDicts)) {
                            Map<String, DictInfo> bubbleDictMap = bubbleDicts.stream().collect(Collectors.toMap(DictInfo::getValue, e -> e));
                            DictInfo bDictInfo = bubbleDictMap.get(Constants.BUBBLE);
                            DictInfo obDictInfo = bubbleDictMap.get(Constants.OPEN_BUBBLE);
                            if (bDictInfo != null) {
                                discardDefect.setBubbleDiscardNum(getDefectNum(Collections.singletonList(bDictInfo), discard, discardField));
                            }
                            if (obDictInfo != null) {
                                discardDefect.setOpenBubbleDiscardNum(getDefectNum(Collections.singletonList(obDictInfo), discard, discardField));
                            }
                        }


                        List<DictInfo> ptDicts = dictMap.get(Constants.PT);
                        if (CollectionUtils.isNotEmpty(ptDicts)) {
                            discardDefect.setPlatinumDiscardNum(getDefectNum(ptDicts, discard, discardField));
                        }

                        List<DictInfo> stoneDicts = dictMap.get(Constants.STONE);
                        if (CollectionUtils.isNotEmpty(stoneDicts)) {
                            discardDefect.setStoneDiscardNum(getDefectNum(stoneDicts, discard, discardField));
                        }

                        discardDefect.setCheckNum(discard.getCheckNum());

                        float bubbleRate = discardDefect.getBubbleDiscardNum() / (float) discard.getCheckNum();
                        discardDefect.setBubbleDiscardRate(bubbleRate);

                        float openBubbleRate = discardDefect.getOpenBubbleDiscardNum() / (float) discard.getCheckNum();
                        discardDefect.setOpenBubbleDiscardRate(openBubbleRate);

                        float ptRate = discardDefect.getPlatinumDiscardNum() / (float) discard.getCheckNum();
                        discardDefect.setPlatinumDiscardRate(ptRate);

                        float stoneRate = discardDefect.getStoneDiscardNum() / (float) discard.getCheckNum();
                        discardDefect.setStoneDiscardRate(stoneRate);
                        discardDefect.setCheckMachineCode(defectReq.getCheckMachineCode());

                        discardDefects.add(discardDefect);
                    }

                    //保存热端、冷端数据
                    if (CollectionUtils.isNotEmpty(discardDefects)) {
                        //判斷是冷端还是热端 0:冷端，1:热端
                        if (Constants.ZERO_STR.equals(checkMachineType)) {
                            //冷端
                            everydayDiscardDefectService.deleteByDate(defectReq);
                            everydayDiscardDefectService.saveBatch(discardDefects);
                        } else {
                            //热端
                            List<EverydayHotEndDiscardDefect> hotEnd = new ArrayList<>();
                            for (EverydayDiscardDefect discardDefect : discardDefects) {
                                EverydayHotEndDiscardDefect everydayHotEndDiscardDefect = new EverydayHotEndDiscardDefect();
                                everydayHotEndDiscardDefect.setDiscardDate(discardDefect.getDiscardDate());
                                everydayHotEndDiscardDefect.setBubbleDiscardNum(discardDefect.getBubbleDiscardNum());
                                everydayHotEndDiscardDefect.setStoneDiscardNum(discardDefect.getStoneDiscardNum());
                                everydayHotEndDiscardDefect.setPlatinumDiscardNum(discardDefect.getPlatinumDiscardNum());
                                everydayHotEndDiscardDefect.setCheckNum(discardDefect.getCheckNum());
                                everydayHotEndDiscardDefect.setBubbleDiscardRate(discardDefect.getBubbleDiscardRate());
                                everydayHotEndDiscardDefect.setStoneDiscardRate(discardDefect.getStoneDiscardRate());
                                everydayHotEndDiscardDefect.setPlatinumDiscardRate(discardDefect.getPlatinumDiscardRate());
                                everydayHotEndDiscardDefect.setCheckMachineCode(discardDefect.getCheckMachineCode());
                                hotEnd.add(everydayHotEndDiscardDefect);
                            }
                            //保存热端数据
                            everydayHotEndDiscardDefectService.deleteByDate(defectReq);
                            everydayHotEndDiscardDefectService.saveBatch(hotEnd);
                        }
                    }
                } else {
                    //没有数据补齐
                    log.error("{}至{} 每日数据为空", startDate, endDate);
                    List<LocalDate> localDates = datePeriod(startDate, endDate);
                    if (Constants.ZERO_STR.equals(defectReq.getCheckMachineType())) {
                        List<EverydayDiscardDefect> everydayDiscardDefectList = new ArrayList<>();
                        for (LocalDate localDate : localDates) {
                            EverydayDiscardDefect everydayDiscardDefect = new EverydayDiscardDefect();
                            everydayDiscardDefect.setCheckMachineCode(defectReq.getCheckMachineCode());
                            everydayDiscardDefect.setDiscardDate(localDate);
                            everydayDiscardDefectList.add(everydayDiscardDefect);
                        }
                        if (CollectionUtils.isNotEmpty(everydayDiscardDefectList)) {
                            //冷端
                            everydayDiscardDefectService.deleteByDate(defectReq);
                            everydayDiscardDefectService.saveBatch(everydayDiscardDefectList);
                        }
                    } else {
                        List<EverydayHotEndDiscardDefect> hotEnd = new ArrayList<>();
                        for (LocalDate localDate : localDates) {
                            EverydayHotEndDiscardDefect everydayHotEndDiscardDefect = new EverydayHotEndDiscardDefect();
                            everydayHotEndDiscardDefect.setCheckMachineCode(defectReq.getCheckMachineCode());
                            everydayHotEndDiscardDefect.setDiscardDate(localDate);
                            hotEnd.add(everydayHotEndDiscardDefect);
                        }
                        if (CollectionUtils.isNotEmpty(hotEnd)) {
                            //热端
                            everydayHotEndDiscardDefectService.deleteByDate(defectReq);
                            everydayHotEndDiscardDefectService.saveBatch(hotEnd);
                        }
                    }
                }
            }
        }
    }


    /**
     * @Description: 获取日期段
     * @version v1.0
     * @author songJinKang
     * @date 2023-09-06 15:53
     */
    @Override
    public List<LocalDate> datePeriod(String startTimeStr, String endTimeStr) {
        if (StringUtils.isNotBlank(startTimeStr) && StringUtils.isNotBlank(endTimeStr)) {
            List<LocalDate> datePeriod = new ArrayList<>();
            LocalDate startTime = LocalDate.parse(startTimeStr, DateTimeFormatter.ISO_LOCAL_DATE);
            LocalDate endTime = LocalDate.parse(endTimeStr, DateTimeFormatter.ISO_LOCAL_DATE);
            long between = ChronoUnit.DAYS.between(startTime, endTime) + 1;
            for (long i = 0; i < between; i++) {
                datePeriod.add(startTime.plusDays(i));
            }
            return datePeriod;
        }
        return Collections.emptyList();
    }


    /***
     * 抽取日常数据用于支撑判废数据查询
     * importHotEndDiscardDefectData 有两个相同地方加锁  防止两边同时执行
     */
    @Override
    @Transactional(rollbackFor = {Exception.class, RuntimeException.class})
    @RedissonLock(key = "#defectReq.checkMachineCode", prefixKey = "importHotEndDiscardDefectData")
    public void importDiscardDefectData(DiscardDefectReq defectReq) {
        log.error("importDiscardDefectData defectReq:{}", defectReq);
        //设置默认时间
        if (defectReq == null) {
            defectReq = setDefaultTime();
        }
        List<Defect> defects = defectGroupService.getByCheckMachine(defectReq.getCheckMachineCode(), defectReq.getCheckMachineType());


        if (CollectionUtils.isNotEmpty(defects)) {
            StringBuilder sql = new StringBuilder();
            AtomicInteger i = new AtomicInteger(1);

            Map<String, List<Defect>> defectMap = defects.stream().collect(Collectors.groupingBy(e -> e.getDefectName() + "_" + e.getDefectCode()));
            String startDate = defectReq.getStartDate();
            String endDate = defectReq.getEndDate();
            String isFinished = defectReq.getIsFinished();
            String checkMachineType = defectReq.getCheckMachineType();
            defectMap.forEach((k, v) -> {
                String[] split = k.split("_");
                String defectCode = split[1];
                String defectName = split[0];

                if (i.get() > 1) {
                    sql.append(" union ");
                }
                sql.append("SELECT CustomerPanelId,DefectName,StartTime as StartTime,MaterialCenterDW,MaterialCenterCW,TiltedSize,TiltedDiv FROM total_equ_data where ");
                sql.append("is_finished = ").append(isFinished);
                sql.append(" AND MachineId ='Inspect' ");
                if (Constants.ZERO_STR.equals(checkMachineType)) {
                    sql.append("AND (CustomerBatchId LIKE '66%' OR CustomerBatchId LIKE '02%')");
                }
                sql.append("AND DefectName = '").append(defectCode).append("' AND(");
                for (int j = 0; j < v.size(); j++) {
                    Defect value = v.get(j);
                    sql.append("(");
                    double minSize = value.getMinSize() / 1000f;
                    double maxSize = value.getMaxSize() / 1000f;
                    sql.append("TiltedSize >= ").append(minSize);
                    sql.append(" AND TiltedSize <= ").append(maxSize);

                    if (Constants.ZERO_STR.equals(checkMachineType)) {
                        sql.append(" AND TiltedDiv >= ").append(value.getMinLayerDepth());
                        sql.append(" AND TiltedDiv <= ").append(value.getMaxLayerDepth());
                    }

                    if (j == v.size() - 1) {
                        sql.append(")");
                    } else {
                        sql.append(") or ");
                    }
                }

                sql.append(") AND DATE_FORMAT(StartTime,'%Y-%m-%d') between ").append("'").append(startDate).append("'").append(" AND ");
                sql.append("'").append(endDate).append("'");
                i.getAndIncrement();
            });

            log.error("支撑判废数据 执行查询语句{}:{}", defectReq.getCheckMachineType().equals(Constants.ZERO_STR) ? "冷端" : "热端", sql);
            List<DiscardDefectData> discardDatas = baseMapper.queryDiscardDefectData(sql.toString());

            //保存热端、冷端数据
            if (CollectionUtils.isNotEmpty(discardDatas)) {
                //判斷是冷端还是热端 0:冷端，1:热端
                if (Constants.ZERO_STR.equals(checkMachineType)) {
                    //冷端
                    discardDefectDataService.deleteByDate(defectReq);
                    discardDefectDataService.saveBatch(discardDatas);
                } else {
                    //热端
                    List<HotEndDiscardDefectData> hotEnd = new ArrayList<>();
                    for (DiscardDefectData discardDefectData : discardDatas) {
                        HotEndDiscardDefectData hotEndDiscardDefectData = new HotEndDiscardDefectData();
                        hotEndDiscardDefectData.setCustomerPanelId(discardDefectData.getCustomerPanelId());
                        hotEndDiscardDefectData.setDefectName(discardDefectData.getDefectName());
                        hotEndDiscardDefectData.setStartTime(discardDefectData.getStartTime());
                        hotEndDiscardDefectData.setMaterialCenterDW(discardDefectData.getMaterialCenterDW());
                        hotEndDiscardDefectData.setMaterialCenterCW(discardDefectData.getMaterialCenterCW());
                        hotEndDiscardDefectData.setTiltedSize(discardDefectData.getTiltedSize());
                        hotEndDiscardDefectData.setTiltedDiv(discardDefectData.getTiltedDiv());
                        hotEnd.add(hotEndDiscardDefectData);
                    }
                    hotEndDiscardDefectDataService.deleteByDate(defectReq);
                    //保存热端数据
                    if (hotEnd.size() >= 10000) {
                        List<List<HotEndDiscardDefectData>> batch = DataUtils.batch(hotEnd, 5000);
                        List<CompletableFuture<Void>> completableFutureList = new ArrayList<>();
                        batch.forEach(e -> {
                            CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> hotEndDiscardDefectDataService.saveBatch(e, 2500),threadPoolTaskExecutor);
                            completableFutureList.add(completableFuture);
                        });
                        log.error("插入线程数：{}", completableFutureList.size());
                        for (CompletableFuture<Void> completableFuture : completableFutureList) {
                            completableFuture.join();
                        }
                    } else {
                        hotEndDiscardDefectDataService.saveBatch(hotEnd);
                    }
                }
            }
        }
    }


    @Override
    @RedissonLock(key = "-1", prefixKey = "importEveryHourDefectLoss")
    public void importEveryHourDefectLoss(DefectLossReq defectLossReq) {
        List<EveryHourDefectLoss> defectLosses = this.queryEveryHourDefectLose(defectLossReq);
        if (CollectionUtils.isNotEmpty(defectLosses)) {
            List<String> timeKey = defectLosses.stream().map(EveryHourDefectLoss::getDefectTimeKey).collect(Collectors.toList());
            List<String> times = new ArrayList<>();
            timeKey.forEach(key -> {
                if (StringUtils.isNotBlank(key)) {
                    times.add(key.substring(0, 8));
                }
            });
            List<String> dates = times.stream().distinct().collect(Collectors.toList());

            Map<String, Integer> receivePackageMap = new HashMap<>();

            for (String date : dates) {
                List<ReceivePackage> receiveDatas = baseMapper.queryTodayReceiveData(date);
                if (CollectionUtils.isNotEmpty(receiveDatas)) {
                    for (ReceivePackage receiveData : receiveDatas) {
                        int count = receiveData.getFxStageCount() + receiveData.getXbStageCount();
                        receivePackageMap.put(receiveData.getHourTime(), count);
                    }
                }
            }
            //Map<String,String> hourKeyMap = hourKeys.stream().collect(Collectors.toMap(h->h,h->h,(h1,h2)->h1));

            //List<EveryHourDefectLoss> newDefectLoss = new ArrayList<>();
            for (EveryHourDefectLoss defectLoss : defectLosses) {
                //if(hourKeyMap.get(defectLoss.getDefectTimeKey())!=null) continue;
                LocalDateTime time = LocalDateTime.parse(defectLoss.getDefectTimeKey().concat("0000"), DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
                defectLoss.setDefectTime(time);
                float hotBubbleRate = DataUtils.isNANOrInfinity(defectLoss.getHotBubbleNum() / (float) defectLoss.getSemiFinishedNum());
                float hotStoneRate = DataUtils.isNANOrInfinity(defectLoss.getHotStoneNum() / (float) defectLoss.getSemiFinishedNum());
                float coldBubbleRate = DataUtils.isNANOrInfinity(defectLoss.getColdBubbleNum() / (float) defectLoss.getFinishedNum());
                float coldOpenBubbleRate = DataUtils.isNANOrInfinity(defectLoss.getColdOpenBubbleNum() / (float) defectLoss.getFinishedNum());
                float coldStoneRate = DataUtils.isNANOrInfinity(defectLoss.getColdStoneNum() / (float) defectLoss.getFinishedNum());
                float platinumLossRate = DataUtils.isNANOrInfinity(defectLoss.getPlatinumNum() / (float) defectLoss.getSemiFinishedNum());
                float bubbleTotalRate;
                float stoneTotalRate;

                if (receivePackageMap.get(defectLoss.getDefectTimeKey()) != null) {
                    defectLoss.setReceiveNum(receivePackageMap.get(defectLoss.getDefectTimeKey()));
                    bubbleTotalRate = DataUtils.isNANOrInfinity((defectLoss.getHotBubbleNum()
                            + defectLoss.getColdBubbleNum()
                            + defectLoss.getReceiveNum() * coldBubbleRate) / (float) defectLoss.getSemiFinishedNum());
                    stoneTotalRate = DataUtils.isNANOrInfinity((defectLoss.getHotStoneNum() + defectLoss.getColdStoneNum()
                            + defectLoss.getReceiveNum() * coldStoneRate) / (float) defectLoss.getSemiFinishedNum());
                } else {
                    defectLoss.setReceiveNum(0);
                    bubbleTotalRate = DataUtils.isNANOrInfinity((defectLoss.getHotBubbleNum() + defectLoss.getColdBubbleNum()) / (float) defectLoss.getSemiFinishedNum());
                    stoneTotalRate = DataUtils.isNANOrInfinity((defectLoss.getHotStoneNum() + defectLoss.getColdStoneNum()) / (float) defectLoss.getSemiFinishedNum());
                }

                float totalRate = platinumLossRate + stoneTotalRate + bubbleTotalRate;

                defectLoss.setBubbleTotalRate(bubbleTotalRate);
                defectLoss.setColdBubbleRate(coldBubbleRate);
                defectLoss.setColdStoneRate(coldStoneRate);
                defectLoss.setHotBubbleRate(hotBubbleRate);
                defectLoss.setHotStoneRate(hotStoneRate);
                defectLoss.setPlatinumLossRate(platinumLossRate);
                defectLoss.setStoneTotalRate(stoneTotalRate);
                defectLoss.setTotalRate(totalRate);
                defectLoss.setColdOpenBubbleRate(coldOpenBubbleRate);

            }
            everyHourDefectLossService.deleteHourData(defectLossReq);
            everyHourDefectLossService.saveBatch(defectLosses);
        }
    }


    @Override
    public void importEverydayDefectLoss(DefectLossReq defectLossReq) {
        log.error("------------执行任务2----------------");
        List<EverydayDefectLoss> defectLosses = this.queryEverydayDefectLose(defectLossReq);
        if (CollectionUtils.isNotEmpty(defectLosses)) {
            for (EverydayDefectLoss defectLoss : defectLosses) {
                LocalDate time = LocalDate.parse(defectLoss.getDefectDateKey(), DateTimeFormatter.ofPattern("yyyyMMdd"));
                defectLoss.setDefectDate(time);
                float hotBubbleRate = DataUtils.isNANOrInfinity(defectLoss.getHotBubbleNum() / (float) defectLoss.getSemiFinishedNum());
                float hotStoneRate = DataUtils.isNANOrInfinity(defectLoss.getHotStoneNum() / (float) defectLoss.getSemiFinishedNum());
                float coldBubbleRate = DataUtils.isNANOrInfinity(defectLoss.getColdBubbleNum() / (float) defectLoss.getFinishedNum());
                float coldOpenBubbleRate = DataUtils.isNANOrInfinity(defectLoss.getColdOpenBubbleNum() / (float) defectLoss.getFinishedNum());
                float coldStoneRate = DataUtils.isNANOrInfinity(defectLoss.getColdStoneNum() / (float) defectLoss.getFinishedNum());
                float platinumLossRate = DataUtils.isNANOrInfinity(defectLoss.getPlatinumNum() / (float) defectLoss.getSemiFinishedNum());


                List<ReceivePackage> receiveDatas = baseMapper.queryTodayReceiveData(defectLoss.getDefectDateKey());
                if (CollectionUtils.isNotEmpty(receiveDatas)) {
                    int receiveNum = 0;
                    for (ReceivePackage receiveData : receiveDatas) {
                        receiveNum = receiveNum + receiveData.getFxStageCount() + receiveData.getXbStageCount();
                    }
                    defectLoss.setReceiveNum(receiveNum);
                }
                float bubbleTotalRate = DataUtils.isNANOrInfinity((defectLoss.getHotBubbleNum() + defectLoss.getColdBubbleNum() + defectLoss.getReceiveNum() * coldBubbleRate) / (float) defectLoss.getSemiFinishedNum());
                float stoneTotalRate = DataUtils.isNANOrInfinity((defectLoss.getHotStoneNum() + defectLoss.getColdStoneNum() + defectLoss.getReceiveNum() * coldStoneRate) / (float) defectLoss.getSemiFinishedNum());
                float totalRate = platinumLossRate + stoneTotalRate + bubbleTotalRate;

                defectLoss.setBubbleTotalRate(bubbleTotalRate);
                defectLoss.setColdBubbleRate(coldBubbleRate);
                defectLoss.setColdStoneRate(coldStoneRate);
                defectLoss.setHotBubbleRate(hotBubbleRate);
                defectLoss.setHotStoneRate(hotStoneRate);
                defectLoss.setPlatinumLossRate(platinumLossRate);
                defectLoss.setStoneTotalRate(stoneTotalRate);
                defectLoss.setTotalRate(totalRate);
                defectLoss.setColdOpenBubbleRate(coldOpenBubbleRate);
            }

            everydayDefectLossService.deleteDayData(defectLossReq);
            everydayDefectLossService.saveBatch(defectLosses);
        }
        log.error("------------执行完成任务2----------------");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @RedissonLock(key = "-1", prefixKey = "importEveryHourColdDirect")
    public void importEveryHourColdDirect(int dayNum) {
        log.error("------------执行任务3----------------");
        for (int i = 0; i < dayNum; i++) {
            String today = LocalDate.now().minusDays(i).format(DateTimeFormatter.ISO_LOCAL_DATE);
            List<EveryHourColdDirectLoss> datas = everyHourColdDirectService.queryTodayData(today);
            List<EveryHourColdDirectLoss> todayData = baseMapper.queryEveryHourColdDirect(today);
            if (CollectionUtils.isNotEmpty(todayData) && CollectionUtils.isNotEmpty(datas)) {
                List<EveryHourColdDirectLoss> newDatas = new ArrayList<>();

                if (CollectionUtils.isNotEmpty(todayData)) {
                    todayData.forEach(d -> {
                        String time = d.getDirectTime().format(DateTimeFormatter.ofPattern("yyyyMMddHH"));
                        d.setHourTimeKey(time);
                    });
                    Map<String, EveryHourColdDirectLoss> todayMap = todayData.stream().collect(Collectors.toMap(EveryHourColdDirectLoss::getHourTimeKey, d -> d, (d1, d2) -> d1));
                    datas.forEach(d -> {
                        String time = d.getDirectTime().format(DateTimeFormatter.ofPattern("yyyyMMddHH"));
                        d.setHourTimeKey(time);
                    });

                    Map<String, EveryHourColdDirectLoss> oldMap = datas.stream().collect(Collectors.toMap(EveryHourColdDirectLoss::getHourTimeKey, d -> d, (d1, d2) -> d1));
                    oldMap.forEach((k, v) -> {
                        EveryHourColdDirectLoss loss = todayMap.get(k);
                        if (loss != null) {
                            long defectNum = loss.getPlatinumTotalNum() + loss.getBubbleTotalNum() + loss.getStoneTotalNum();
                            float platinumBoardNum = loss.getPlatinumTotalNum() / (float) loss.getCheckNum();
                            float stoneBoardNum = loss.getStoneTotalNum() / (float) loss.getCheckNum();
                            float bubbleBoardNum = loss.getBubbleTotalNum() / (float) loss.getCheckNum();
                            float openBubbleBoardNum = loss.getOpenBubbleTotalNum() / (float) loss.getCheckNum();
                            float defectBoardNum = defectNum / (float) loss.getCheckNum();
                            loss.setDefectTotalNum(defectNum);
                            loss.setPlatinumBoardNum(platinumBoardNum);
                            loss.setStoneBoardNum(stoneBoardNum);
                            loss.setBubbleBoardNum(bubbleBoardNum);
                            loss.setDefectBoardNum(defectBoardNum);
                            loss.setOpenBubbleBoardNum(openBubbleBoardNum);
                            newDatas.add(loss);
                            todayMap.remove(k);
                        } else {
                            newDatas.add(v);
                        }
                    });

                    if (CollectionUtils.isNotEmpty(todayMap)) {
                        todayMap.forEach((k, v) -> {
                            newDatas.add(v);
                        });
                    }

                    everyHourColdDirectService.removeByIds(datas.stream().map(EveryHourColdDirectLoss::getId).collect(Collectors.toList()));

                    if (CollectionUtils.isNotEmpty(newDatas)) {
                        everyHourColdDirectService.saveBatch(newDatas);
                    }
                }
            } else {
                if (CollectionUtils.isNotEmpty(todayData)) {
                    for (EveryHourColdDirectLoss data : todayData) {
                        if (data != null) {
                            long defectNum = data.getPlatinumTotalNum() + data.getBubbleTotalNum() + data.getStoneTotalNum();
                            float platinumBoardNum = data.getPlatinumTotalNum() / (float) data.getCheckNum();
                            float stoneBoardNum = data.getStoneTotalNum() / (float) data.getCheckNum();
                            float bubbleBoardNum = data.getBubbleTotalNum() / (float) data.getCheckNum();
                            float openBubbleBoardNum = data.getOpenBubbleTotalNum() / (float) data.getCheckNum();
                            float defectBoardNum = defectNum / (float) data.getCheckNum();
                            data.setDefectTotalNum(defectNum);
                            data.setPlatinumBoardNum(platinumBoardNum);
                            data.setStoneBoardNum(stoneBoardNum);
                            data.setBubbleBoardNum(bubbleBoardNum);
                            data.setDefectBoardNum(defectBoardNum);
                            data.setOpenBubbleBoardNum(openBubbleBoardNum);
                        }
                    }
                    everyHourColdDirectService.saveBatch(todayData);
                }
            }
        }
        log.error("------------执行完成任务3----------------");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importEverydayColdDirect(int dayNum) {
        log.error("------------执行任务4----------------");
        for (int i = 0; i < dayNum; i++) {
            String today = LocalDate.now().minusDays(i).format(DateTimeFormatter.ISO_LOCAL_DATE);
            List<EverydayColdDirectLoss> old = everydayColdDirectService.queryTodayData(today);
            EverydayColdDirectLoss todayData = baseMapper.queryEverydayHourColdDirect(today);
            if (todayData != null) {
                long defectNum = todayData.getPlatinumTotalNum() + todayData.getBubbleTotalNum() + todayData.getStoneTotalNum();
                float platinumBoardNum = todayData.getPlatinumTotalNum() / (float) todayData.getCheckNum();
                float stoneBoardNum = todayData.getStoneTotalNum() / (float) todayData.getCheckNum();
                float bubbleBoardNum = todayData.getBubbleTotalNum() / (float) todayData.getCheckNum();
                float openBubbleBoardNum = todayData.getOpenBubbleTotalNum() / (float) todayData.getCheckNum();
                float defectBoardNum = defectNum / (float) todayData.getCheckNum();
                todayData.setDefectTotalNum(defectNum);
                todayData.setPlatinumBoardNum(platinumBoardNum);
                todayData.setStoneBoardNum(stoneBoardNum);
                todayData.setBubbleBoardNum(bubbleBoardNum);
                todayData.setDefectBoardNum(defectBoardNum);
                todayData.setOpenBubbleBoardNum(openBubbleBoardNum);
                if (CollectionUtils.isNotEmpty(old)) {
                    everydayColdDirectService.removeByIds(old.stream().map(EverydayColdDirectLoss::getId).collect(Collectors.toList()));
                }
                //保存
                everydayColdDirectService.save(todayData);
            }
            log.error("------------执行完成任务4----------------");
        }
    }


    /**
     * @Description: 设置默认时间
     * @version v1.0
     * @author songJinKang
     * @date 2023-09-06 10:57
     */
    public static DiscardDefectReq setDefaultTime() {
        LocalDate now = LocalDate.now();
        String startDate = now.minusDays(2).format(DateTimeFormatter.ISO_LOCAL_DATE);
        String endDate = now.plusDays(1).format(DateTimeFormatter.ISO_LOCAL_DATE);
        DiscardDefectReq defectReq = new DiscardDefectReq();
        defectReq.setStartDate(startDate);
        defectReq.setEndDate(endDate);
        return defectReq;
    }

    /***
     * 根据字段名获取字段值
     * @param dictInfos
     * @param discard
     * @param discardField
     * @return
     */
    @Override
    public int getDefectNum(List<DictInfo> dictInfos, DiscardData discard, Map<String, String> discardField) {
        int bubbleCount = 0;
        for (DictInfo dict : dictInfos) {
            String field = discardField.get(dict.getValue());
            if (StringUtils.isNotBlank(field)) {
                try {
                    Object obj = DataUtils.getByFieldName(discard, field);
                    if (obj != null) {
                        int count = Integer.parseInt(obj.toString());
                        bubbleCount = bubbleCount + count;
                    }

                } catch (Exception e) {
                    log.info("根据字段名称获取字段值报错:" + e.getMessage());
                }
            }
        }
        return bubbleCount;
    }

}
